import { makeAutoObservable, makeObservable, observable, action, computed, runInAction, when, reaction, autorun } from 'mobx'

// mobx使用一个类来管理他的State.
class doctorStore {
  // 初始化的状态
  doctorList = []
  count = 0
  userInfo = { uid: 1, uname: 'wenqingwu', usex: '男' }

  constructor() {
    // this.increment = this.increment.bind(this)
    // 手动配置哪些属性、方法使用mobx要管理的。
    makeObservable(
      this,
      // 参数2,表示要管理的store的内容
      {
        doctorList: observable, // 定义一个需要（可）跟踪的属性，当doctorList改变时，页面就会重新渲染。只有设定未 observable时，才会监听状态的改变。
        count: observable,
        userInfo: observable,
        increment: action.bound,  // 表示这是一个actions函数， .bound,可以理解未修改类里面的函数的this的指向，让this指向实例化对象
        changeUserInfo: action.bound,
        changeDoctors: action.bound,
        getDoctors: action.bound,
        getUserName: computed, // 计算属性，当状态改变时，自动重新去获取新的uname.
      }
    )
    // 2. 自动管理
    // makeAutoObservable(this) // 自动进行断言，识别属性和方法是不是要跟踪的状态或计算属性或Action.

    // 监听器：when, reaction, autorun
    // 1 when(callback1, callback2), callback1,返回要监听的状态； callback2是监听状态改变时，执行的逻辑。
    //   when(),只会执行一次。 类似于jQuery里面的once().
    when(() => this.count, () => {
      console.log('count的改变', this.count);
    })
    // 2. reaction(callback1, callback2), 语法和when()相同，作用不同。 reaction（）会一直监听状态的改变。
    reaction(()=>this.count, ()=>{
      console.log('reaction()里面监听到count的改变', this.count);
    })
    // 3. when, reaction都必须写在constructor()里面。
    // 4. autorun(callback),必须要写明要监听的状态,即再函数中用到了哪个state,就自动监听它的变化.
    autorun(()=>{
      // 自动监听callback里面要操作的state。
      // console.log('autorun里面的count监听：',this.count);
      console.log('autorun里面的userInfo监听：',this.userInfo.uname);
    })
// 可以分别监听不同的状态，执行不同的逻辑。
    autorun(()=>{
      // 自动监听callback里面要操作的state。
      console.log('类里面的autorun里面的count监听：',this.count);
      
    })
  }
  // 3. 计算属性: 关键字 get 写在函数名称的左边
  get getUserName() {
    return this.userInfo.uname + "," + (this.userInfo.usex === '男' ? '帅哥' : '美女')
    // return this.userInfo.uname
  }
  // actions,就是类里面的方法
  increment() {
    this.count = this.count + 1;
  }
  // 异步的actions
  getDoctors() {
    // 要注意一点，就是再异步请求时，要用到this. 用箭头函数来确保this指向类的实例化对象。
    fetch('http://127.0.0.1:80/doctor/noteamall', { method: 'get' })
      .then(res => res.json())
      .then(res => {
        console.log(res);
        if (res.code === 0) {
          // 再异步action里面，必须要使用runInAction()来修改状态。
          //  使用这个工具函数来创建一个会被立即调用的临时 action。在异步进程中非常有用。参数就是临时 action函数
          runInAction(() => {
            this.doctorList = res.data;
          })
        }
      })
  }
  // 如果把fetch()放在组件中，不做异步的actions，就需要写一个同步的action方法：
  changeDoctors(list) {
    this.doctorList = list;
  }
  // 修改changeUserInfo的action函数
  changeUserInfo(obj) {
    this.userInfo = obj
  }

}
// console.log(new doctorStore());
// 如果autorun写在类的外面，就需要单独new一个类的实例化对象，同时公开这个实例化对象。
let store =  new doctorStore()
autorun(()=>{
  console.log('constructor外面的autorun里面的count监听：',store.count);
})
// export default new doctorStore();
// 确保公开出来是同一个实例化对象
export default store;